from collections import namedtuple
from hashlib import sha1

from bencoding import Decoder, Encoder

TorrentFile = namedtuple('TorrentFile', ['name', 'length'])

class Torrent:
    def __init__(self, filename: str) -> None:
        self.filename = filename
        self.files = []

        with open(self.filename, 'rb') as f:
            meta_info = f.read()
            self.meta_info = Decoder(meta_info).decode()
            info = Encoder(self.meta_info[b'info']).encode()
            self.info_hash = sha1(info).digest()
            self._identify_files()

        # init pieces
        data = self.meta_info[b'info'][b'pieces']
        pieces = []
        offset = 0
        length = len(data)

        while offset < length:
            # each piece in pieces is exactly 20 bytes
            pieces.append(data[offset : offset + 20])
            offset += 20
        self.pieces = pieces
    
    def _identify_files(self):
        if self.multi_file:
            raise NotImplementedError()
        self.files.append(
            TorrentFile(
                self.meta_info[b'info'][b'name'].decode('utf-8'),
                self.meta_info[b'info'][b'length']
                )
            )
    @property
    def comment(self) -> str:
        return self.meta_info.get(b'comment', b'').decode('utf-8')

    @property
    def announce(self) -> str:
        return self.meta_info.get(b'announce', b'').decode('utf-8')
    
    @property
    def multi_file(self) -> bool:
        return b'files' in self.meta_info[b'info']
    
    @property
    def piece_length(self) -> int:
        return self.meta_info[b'info'][b'piece length']
    
    @property
    def total_size(self) -> int:
        if self.multi_file:
            raise NotImplementedError()
        return self.files[0].length
    
    @property
    def output_file(self):
        return self.meta_info[b'info'][b'name'].decode('utf-8')
    
    def __str__(self) -> str:
        return '{:>20} : {}\n' \
               '{:>20} : {}\n' \
               '{:>20} : {}\n' \
               '{:>20} : {}\n' \
               '{:>20} : {}\n' \
               '{:<20}\n' \
               '{:>20} : {}\n' \
               '{:>20} : {}\n'.format('comment', self.comment,
                                      'announce', self.announce,
                                      'created by', self.meta_info[b'created by'].decode('utf-8'),
                                      'creation date', self.meta_info[b'creation date'],
                                      'info hash(SHA-1)', self.info_hash,
                                      'FILE LIST',
                                      'name', self.meta_info[b'info'][b'name'].decode('utf-8'),
                                      'bytes', self.meta_info[b'info'][b'length']
                                      )